﻿using System;
using System.Data;
using NHibernate;
using SellAndBuy.Infrastructure.Core.Logging;
using SellAndBuy.Infrastructure.Data.Core.Factories;
using SellAndBuy.Infrastructure.Data.Core.Resources;

// ReSharper disable CheckNamespace
namespace SellAndBuy.Infrastructure.Data.Core
// ReSharper restore CheckNamespace
{
    /// <summary>
    /// Unit of work implementation using NHibernate
    /// </summary>
    public class UnitOfWork : INhibernateUnitOfWork
    {
        private readonly NHibernateFactory _factory;
        //private readonly ILogger _logger;
        private ITransaction _transaction;

        public ISession Session { get; private set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="nHibernateFactory">NHibernate factory</param>
        /// <param name="logger">Logger</param>
        /// <exception cref="ArgumentNullException"><paramref name="nHibernateFactory" /> is <c>null</c>.</exception>
        public UnitOfWork(NHibernateFactory nHibernateFactory/*, ILogger logger*/)
        {
            if (nHibernateFactory == null)
                throw new ArgumentNullException("nHibernateFactory");

            //if (logger == null)
            //    throw new ArgumentNullException("logger");

            _factory = nHibernateFactory;
            //_logger = logger;
            Session = nHibernateFactory.SessionFactory.OpenSession();
            //_session.FlushMode = FlushMode.Commit;

            _transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
        }

        /// <summary>
        /// Close session
        /// </summary>
        public void Dispose()
        {
            Session.Close();
        }

        /// <summary>
        /// Commit changes to database
        /// </summary>
        /// <exception cref="InvalidOperationException"><c>InvalidOperationException</c>.</exception>
        public void Commit()
        {
            if (!_transaction.IsActive)
                throw new InvalidOperationException(Messages.exception_NoActiveTransaction);

            try
            {
                _transaction.Commit();
            }
            catch (Exception ex)
            {
                //_logger.Error(this.GetType().ToString(), 
                //    "Error while commiting transaction, Rolling back and restart transaction", ex);

                _transaction.Rollback();
                throw;
            }
            finally
            {
                Session.Close();
                Session = _factory.SessionFactory.OpenSession();
                _transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
            }
        }

        /// <summary>
        /// Rollback changes to database
        /// </summary>
        /// <returns></returns>
        public void Rollback()
        {
            if (_transaction.IsActive)
            {
                _transaction.Rollback();
                _transaction = Session.BeginTransaction(IsolationLevel.ReadCommitted);
            }
            else
            {
                //_logger.Warn(this.GetType().ToString(),
                //             "Rolling back non-active transaction, rollback not performed");
            }
        }
    }
}